/**
 * MIT License
 * 
 * Copyright (c) 2024 - present @ ebraid
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef __EB_SYSLOG_H__
#define __EB_SYSLOG_H__

#include <config.h>


#ifdef __cplusplus
extern "C" {
#endif


#define SYSLOG_LEVEL_TRACE            0 /**< A lot of logs to give detailed information*/
#define SYSLOG_LEVEL_INFO             1 /**< Log important events*/
#define SYSLOG_LEVEL_WARN             2 /**< Log if something unwanted happened but didn't caused problem*/
#define SYSLOG_LEVEL_ERROR            3 /**< Only critical issue, when the system may fail*/
#define SYSLOG_LEVEL_USER             4 /**< Custom logs from the user*/
#define SYSLOG_LEVEL_NONE             5 /**< Do not log anything*/
#define _SYSLOG_LEVEL_NUM             6 /**< Number of log levels*/


/**
 * @brief ebraid log printing function, used to print debugging information. Note that this function 
 *        should only be called in debugging mode, otherwise it may affect system real-time 
 *        performance due to long execution time
 * 
 * @param level:  log level, such as, INFO, USER...
 * @param format:  log content
 * 
 * @return none
*/
void syslog(const char *level, const char * format, ...);


struct uart_device;

/**
 * @brief binding serial port devices to system logs
 *        In general, it is necessary to register a serial device and use this function to bind system logs
 * 
 * @param dev: uart device
 */
void syslog_bind_uart_device(struct uart_device *dev);


/**
 * @brief get serial port devices for system logs
 * 
 * @param none
 */
struct uart_device* syslog_device(void);


#if CONFIG_SYSLOG
#if CONFIG_SYSLOG_COLOR

#define NONE                           "\033[0m"
#define RED                            "\033[31m"
#define GREEN                          "\033[32m"
#define YELLOW                         "\033[33m"
#define BLUE                           "\033[34m"
#define PURPLE                         "\033[35m"
#define CYAN                           "\033[36m"
#define WHITE                          "\033[37m"
#define LIGHT_BLUE                     "\033[1;34m"


#define SYSLOG_TRACE_FLAG              BLUE"[TRACE]"NONE
#define SYSLOG_INFO_FLAG               GREEN"[INFO]"NONE
#define SYSLOG_WARN_FLAG               YELLOW"[WARN]"NONE
#define SYSLOG_ERROR_FLAG              RED"[ERROR]"NONE
#define SYSLOG_USER_FLAG               PURPLE"[USER]"NONE
#define SYSASSERT_FLAG                 CYAN"[ASSERT]"NONE

#define DEBUG_TRACE_FLAG               LIGHT_BLUE"[DEBUG]"NONE

#else
#define SYSLOG_TRACE_FLAG              "[TRACE] "
#define SYSLOG_INFO_FLAG               "[INFO] "
#define SYSLOG_WARN_FLAG               "[WARN] "
#define SYSLOG_ERROR_FLAG              "[ERROR] "
#define SYSLOG_USER_FLAG               "[USER] "
#define SYSASSERT_FLAG                 "[ASSERT] "
#define DEBUG_TRACE_FLAG               "[DEBUG]"

#endif //CONFIG_SYSLOG_COLOR


#ifndef SYSLOG_TRACE
#    if CONFIG_SYSLOG_LEVEL <= SYSLOG_LEVEL_TRACE
#        define SYSLOG_TRACE(...) syslog(SYSLOG_TRACE_FLAG, __VA_ARGS__)
#    else
#        define SYSLOG_TRACE(...) do {}while(0)
#    endif
#endif

#ifndef SYSLOG_INFO
#    if CONFIG_SYSLOG_LEVEL <= SYSLOG_LEVEL_INFO
#        define SYSLOG_INFO(...) syslog(SYSLOG_INFO_FLAG,  __VA_ARGS__)
#    else
#        define SYSLOG_INFO(...) do {}while(0)
#    endif
#endif

#ifndef SYSLOG_WARN
#    if CONFIG_SYSLOG_LEVEL <= SYSLOG_LEVEL_WARN
#        define SYSLOG_WARN(...) syslog(SYSLOG_WARN_FLAG, __VA_ARGS__)
#    else
#        define SYSLOG_WARN(...) do {}while(0)
#    endif
#endif

#ifndef SYSLOG_ERROR
#    if CONFIG_SYSLOG_LEVEL <= SYSLOG_LEVEL_ERROR
#        define SYSLOG_ERROR(...) syslog(SYSLOG_ERROR_FLAG, __VA_ARGS__)
#    else
#        define SYSLOG_ERROR(...) do {}while(0)
#    endif
#endif

#ifndef SYSLOG_USER
#    if CONFIG_SYSLOG_LEVEL <= SYSLOG_LEVEL_USER
#        define SYSLOG_USER(...) syslog(SYSLOG_USER_FLAG,  __VA_ARGS__)
#    else
#        define SYSLOG_USER(...) do {}while(0)
#    endif
#endif

#if CONFIG_SYSLOG_LEVEL < SYSLOG_LEVEL_NONE
#    define SYSLOG(...) syslog(__VA_ARGS__)
#else
#    define SYSLOG(...) do {} while(0)
#endif


/**
 * @brief ebraid assert handler, used to handle assertions
 * 
 * @param file:  file name
 * @param func:  function name
 * @param line:  line number
 * 
 * @return none
*/
void eb_assert_handler(const char *file, const char *func, int line);

#define SYSASSERT(condition)         \
        do {                         \
            if(!(condition)) {       \
                eb_assert_handler(__FILE__, __FUNCTION__, __LINE__); \
            }                        \
        } while(0)


#else // if no define debug mode macro

#define SYSLOG_TRACE(...) do {}while(0)
#define SYSLOG_INFO(...) do {}while(0)
#define SYSLOG_WARN(...) do {}while(0)
#define SYSLOG_ERROR(...) do {}while(0)
#define SYSLOG_USER(...) do {}while(0)
#define SYSLOG(...) do {}while(0)

#define SYSASSERT(condition) do {}while(0)

#endif


#if CONFIG_DEBUG
#define DEBUG_TRACE(...) syslog(DEBUG_TRACE_FLAG, __VA_ARGS__)
#else
#define DEBUG_TRACE(...) do {}while(0)
#endif


#ifdef __cplusplus
} /*extern "C"*/
#endif

#endif //!__EB_SYSLOG_H__
